#include "lua_hooks.h"
#include "battlestats.h"
#include "c_lua_interface.h"

CGameInterface * g_pGameInterface;

std::map< std::string, CFontMaterial * > m_MappedFonts;
std::map< std::string, CMaterial * > m_MappedTextures;

CFontMaterial * GetFont( std::string font )
{
	
	CFontMaterial * fontmat = NULL;
	
	try
	{
		
		fontmat = m_MappedFonts.at( font );
		
	} catch( std::exception & err )
	{
	
		fontmat = g_pGameInterface->Graphics()->GetFont( font );
		
		if( !fontmat )
			return NULL;
		else
		{
			
			m_MappedFonts[font] = fontmat;
			
		}
		
	}
	
	return fontmat;
	
}

//This is called at game state initialization, as opposed to CreateLuaHooks, which is called once in the application
void CGameInterface::RegisterLuaEngineHooks()
{
	
	RegisterNameSpace( m_pLuaState, "Base" ); 
	
	RegisterNameSpace( m_pLuaState, "Engine" );
		RegisterNameSpaceFunction( m_pLuaState, "Engine", "AddBattleStats", LUAENGINE_AddBattleStats );
		RegisterNameSpaceFunction( m_pLuaState, "Engine", "BindGameCameraToEntity", LUAENGINE_BindGameCameraToEnt );
		RegisterNameSpaceFunction( m_pLuaState, "Engine", "StartBattle", LUAENGINE_StartBattle );
		RegisterNameSpaceFunction( m_pLuaState, "Engine", "LockBattle", LUAENGINE_LockBattle );
		RegisterNameSpaceFunction( m_pLuaState, "Engine", "UnlockBattle", LUAENGINE_UnlockBattle );
		RegisterNameSpaceFunction( m_pLuaState, "Engine", "GetBattlePlayer", LUAENGINE_GetBattlePlayer );
		RegisterNameSpaceFunction( m_pLuaState, "Engine", "EndBattle", LUAENGINE_EndBattle );
	
}

void CGameInterface::CreateLuaHooks()
{

	RegisterNameSpace( m_pLuaState, "LuaC" );
	RegisterNameSpace( m_pLuaState, "G" );
	
	RegisterFunction( m_pLuaState, "GetTicks", LUA_getticks );
	RegisterFunction( m_pLuaState, "include", LUA_include );
	RegisterFunction( m_pLuaState, "GetDPS", LUA_getdps );
	RegisterFunction( m_pLuaState, "GetStringWidth", LUA_getstringsize );
	RegisterFunction( m_pLuaState, "LoadMap", LUA_loadmap );
	RegisterFunction( m_pLuaState, "GetCameraPos", LUA_getcamerapos );
	RegisterFunction( m_pLuaState, "SetCameraPos", LUA_setcamerapos );
	RegisterFunction( m_pLuaState, "LockCamera", LUA_lockcamera );
	RegisterFunction( m_pLuaState, "UnlockCamera", LUA_unlockcamera );
	RegisterFunction( m_pLuaState, "GetPlayer", LUA_getplayer );
	RegisterFunction( m_pLuaState, "GetPreviousMap", LUA_getpreviousmap );
	RegisterFunction( m_pLuaState, "GetCurrentMap", LUA_getcurrentmap );
	RegisterFunction( m_pLuaState, "SetGameRule", LUA_setgamerule );
	RegisterFunction( m_pLuaState, "GetMousePos", LUA_getmousepos );
	
	RegisterNameSpace( m_pLuaState, "Draw" );
		RegisterNameSpaceFunction( m_pLuaState, "Draw", "Rect", LUA_DrawRect );
		RegisterNameSpaceFunction( m_pLuaState, "Draw", "SetColor", LUA_DrawSetColor );
		RegisterNameSpaceFunction( m_pLuaState, "Draw", "SetColor255", LUA_DrawSetColor255 );
		RegisterNameSpaceFunction( m_pLuaState, "Draw", "Text", LUA_DrawText );
		RegisterNameSpaceFunction( m_pLuaState, "Draw", "Texture", LUA_DrawTexture );
		RegisterNameSpaceFunction( m_pLuaState, "Draw", "BindTexture", LUA_bindtexture );
		
	g_pGameInterface = this;
	
	Log::Debug( "Registered Lua Hooks" );
	
}

int LUA_loadmap( lua_State * s )
{
	
	std::string map = lua_tostring( s, 1 );
	
	g_pGameInterface->LoadMap( map );
	
	return 0;
	
}


int LUA_setgamerule( lua_State * s )
{
	
	std::string k = lua_tostring( s, 1 );
	int v = lua_tonumber( s, 2 );
	
	g_pGameInterface->GetGameRules()->SetGameRule( k, v );
	
	return 0;
	
}

int LUA_getplayer( lua_State * s )
{
	
	CEntity * p = g_pGameInterface->GetPlayer();
	
	lua_newtable( s );
	lua_pushnumber( s, p->GetUniqueID() );
	lua_setfield( s, -2, "id" );
	
	lua_newtable( s );
	lua_getglobal( s, "Entity" );
	lua_setfield( s, -2, "__index" );
	lua_setmetatable( s, -2 );
	
	return 1;
	
}

int LUA_getpreviousmap( lua_State * s )
{
	
	lua_pushstring( s, g_pGameInterface->GetPreviousMapName().c_str() );
	
	return 1;
	
}

int LUA_getcurrentmap( lua_State * s )
{
	
	lua_pushstring( s, g_pGameInterface->GetCurMapName().c_str() );
	
	return 1;
	
}

int LUA_lockcamera( lua_State * s )
{
	
	g_pGameInterface->GetGameCamera()->Lock();
	
	return 0;
	
}

int LUA_unlockcamera( lua_State * s )
{
	
	g_pGameInterface->GetGameCamera()->Unlock();
	
	return 0;
	
}

int LUA_setcamerapos( lua_State * s )
{

	float x = lua_tonumber( s, 1 );
	float y = lua_tonumber( s, 2 );
	
	g_pGameInterface->GetGameCamera()->SetCameraTranslation( x, y );
	
	return 0;
	
}

int LUA_getcamerapos( lua_State * s )
{
	
	Vector2D pos = g_pGameInterface->GetGameCamera()->GetCurTranslation();
	
	lua_newtable( s );
	lua_pushnumber( s, pos.x );
	lua_setfield( s, -2, "x" );
	lua_pushnumber( s, pos.y );
	lua_setfield( s, -2, "y" );
	
	
	return 1;
	
}

int LUA_getmousepos( lua_State * s )
{
	
	int x, y;
	
	SDL_GetMouseState( &x, &y );
	
	lua_newtable( s );
	lua_pushnumber( s, x );
	lua_setfield( s, -2, "x" );
	lua_pushnumber( s, y );
	lua_setfield( s, -2, "y" );
	
	return 1;
	
}

int LUA_getstringsize( lua_State * s )
{
	
	std::string font = ( char * )lua_tostring( s, 1 );
	std::string str = ( char * )lua_tostring( s, 2 );
	
	CFontMaterial * fontmat = GetFont( font );
	
	lua_pushnumber( s, fontmat->GetStringWidth( str ) );
	
	return 1;
	
}

int LUAENGINE_StartBattle( lua_State * s )
{
	
	int size = lua_rawlen( s, 1 );
	
	Lua::GenerateBattleTable();
		
	for( int j = 1; j <= size; j++ )
	{
		
		lua_pushnumber( s, j );
		lua_gettable( s, 1 );
		std::string ptype = lua_tostring( s, -1 );
		lua_pop( s, 1 );
		
		g_pGameInterface->AddBattleEntity( 0, ptype );
		
	}
	
	size = lua_rawlen( s, 2 );
	
	for( int j = 1; j <= size; j++ )
	{
		
		lua_pushnumber( s, j );
		lua_gettable( s, 2 );
		std::string etype = lua_tostring( s, -1 );
		lua_pop( s, 1 );
		
		g_pGameInterface->AddBattleEntity( 1, etype );
		
	}
	
	if( lua_gettop( s ) > 2 )
	{
		
		if( lua_gettop( s ) > 3 )
		{
			
			if( !LuaNil( s ) )
			{
				
				int exit_func = luaL_ref( s, LUA_REGISTRYINDEX );
				g_pGameInterface->BattleSystem()->SetBattleExitFunc( exit_func );
				
			} else
				lua_pop( s, 1 );
			
		}
		
		if( !LuaNil( s ) )
		{
			
			int think_func = luaL_ref( s, LUA_REGISTRYINDEX );
			g_pGameInterface->BattleSystem()->SetBattleThinkFunc( think_func );
			
		} else
			lua_pop( s, 1 );
		
	}
	
	g_pGameInterface->BattleSystem()->SetCurBattlePlayer( 0 );
	g_pGameInterface->BattleSystem()->StartBattle();
	
	return 0;
}

int LUAENGINE_GetBattlePlayer( lua_State * s )
{
	
	int n = lua_tonumber( s, 1 );
	
	CBattleEntity * e = g_pGameInterface->BattleSystem()->GetBattlePlayer( n );
	
	lua_newtable( s );
	
	lua_pushnumber( s, e->GetUniqueID() );
	lua_setfield( s, -2, "id" );
	
	lua_newtable( s );
	lua_getglobal( s, "Entity" );
	lua_setfield( s, -2, "__index" );
	
	lua_setmetatable( s, -2 );
	
	return 1;
	
	
}

int LUAENGINE_EndBattle( lua_State * s )
{
	
	bool b = false;
	
	if( lua_gettop( s ) >= 1 )
		b = lua_toboolean( s, 1 );
	
	if( b )
		g_pGameInterface->BattleSystem()->TurnoffOutro();
		
	g_pGameInterface->BattleSystem()->EndBattle();
	
	return 0;
	
}

int LUAENGINE_LockBattle( lua_State * s )
{
	
	g_pGameInterface->BattleSystem()->LockBattle();
	
	return 0;
	
}

int LUAENGINE_UnlockBattle( lua_State * s )
{
	
	g_pGameInterface->BattleSystem()->UnlockBattle();
	
	return 0;
	
}
	

int LUAENGINE_BindGameCameraToEnt( lua_State * s )
{
	
	
	int id = LuaStringKeyIntValue( s, 1, "id" );

	CEntity * e = g_pGameInterface->GetEntityFactory()->GetStateVec()->GetEntity( id );
	
	g_pGameInterface->GetGameCamera()->BindCameraToEntity( e );
	
	return 0;
	
}

int LUAENGINE_AddBattleStats( lua_State * s )
{
	
	if( lua_istable( s, 1 ) )
	{
		
		int c = lua_rawlen( s, 1 ) + 1;
		
		for( int j = 1; j < c; j++ )
		{
			
			lua_pushnumber( s, j );
			lua_gettable( s, 1 );
			
				std::string name = LuaStringKeyStringValue( s, -1, "Name" );
				std::string nicename = LuaStringKeyStringValue( s, -1, "NiceName" );
				
				int hp = LuaStringKeyIntValue( s, -1, "HP" );
				
				int pwr = LuaStringKeyIntValue( s, -1, "Power" );
				int def = LuaStringKeyIntValue( s, -1, "Defense" );
				int spd = LuaStringKeyIntValue( s, -1, "Speed" );
				int luck = LuaStringKeyIntValue( s, -1, "Luck" );
				
				float scale = LuaStringKeyFloatValue( s, -1, "Scale" );
				
				int idleanim = LuaStringKeyIntValue( s, -1, "IdleAnimID" );	
			
				CBattleCharacterData * b = new CBattleCharacterData;
				
				b->SetNames( name, nicename );
				b->SetHealth( hp );
				b->SetStats( pwr, def, spd, luck );
				b->SetScale( scale );
				
				lua_pushstring( s, "Sprites" );
				lua_gettable( s, 2 );
				
				int sc = lua_rawlen( s, -1 ) + 1;
				
				for( int i = 1; i < sc; i++ )
				{
					
					lua_pushnumber( s, i );
					lua_gettable( s, 3 );
					
					std::string dir = lua_tostring( s, -1 );
					
					CMaterial * mat = g_pGameInterface->Graphics()->Find( dir );
					
					b->AddSprite( mat );
					
					lua_pop( s, 1 );
					
				}
				
				lua_pop( s, 1 );
				
				lua_pushstring( s, "MoveSet" );
				lua_gettable( s, 2 );
				
				int mc = lua_rawlen( s, -1 ) + 1;
				
				for( int j = 1; j < mc; j++ )
				{
					
					lua_pushnumber( s, j );
					lua_gettable( s, 3 );
					
					int moveid = LuaStringKeyIntValue( s, -1, "ID" );
					int animid = LuaStringKeyIntValue( s, -1, "AnimID" );
					int repeatmin = LuaStringKeyIntValue( s, -1, "RepeatMin" );
					int repeatmax = LuaStringKeyIntValue( s, -1, "RepeatMax" );
					float dmgmin = LuaStringKeyFloatValue( s, -1, "DmgMin" );
					float dmgmax = LuaStringKeyFloatValue( s, -1, "DmgMax" );
					std::string menutext = LuaStringKeyStringValue( s, -1, "MenuText" );
					std::string movetext = LuaStringKeyStringValue( s, -1, "Text" );
					
					lua_getfield( s, -1, "Think" );
					int thinkfunc = luaL_ref( s, LUA_REGISTRYINDEX );
					
					CBattleAttackData * ad = new CBattleAttackData;
					
					ad->SetID( moveid );
					ad->SetAnimID( animid );
					ad->SetRepeatRange( repeatmin, repeatmax );
					ad->SetDamageRange( dmgmin, dmgmax );
					ad->SetMoveText( movetext );
					ad->SetThinkFuncID( thinkfunc );
					ad->SetMenuText( menutext );
					
					b->AddMove( moveid, ad );
					
					lua_pop( s, 1 );
					
				}
				
				lua_pop( s, 1 );
				
				g_pGameInterface->BattleSystem()->GetBattleStats()->AddStat( b );
				
				int datatable = luaL_ref( s, LUA_REGISTRYINDEX );
				
				b->SetLuaDataTable( datatable );
				
		//	lua_pop( s, 1 );
			
		}
		
		
	}
	
	lua_pop( s, 1 );
	
	return 0;
	
}

int LUA_getticks( lua_State * s )
{
	
	lua_pushnumber( s, SDL_GetTicks() );

	return 1;
	
}

int LUA_include( lua_State * s )
{
	
	std::string luafile = ( char * )lua_tostring( s, 1 );
	g_pGameInterface->OpenScript( ( "lua/" + luafile ).c_str() );
	
	return 0;
	
}

int LUA_getdps( lua_State * s )
{
	
	lua_pushnumber( s, g_pGameInterface->GetDPS() );
	
	return 1;
	
}

int LUA_DrawRect( lua_State * s )
{
	
	float x = lua_tonumber( s, 1 ); 
	float y = lua_tonumber( s, 2 );
	int w = lua_tonumber( s, 3 );
	int h = lua_tonumber( s, 4 );

	Draw::DisableTextures();
	
	Draw::Quad( x, y, 0.0f, w, h );
	
	Draw::EnableTextures();
	
	return 0;

}

int LUA_DrawSetColor255( lua_State * s )
{
	
	float r = lua_tonumber( s, 1 );
	float g = lua_tonumber( s, 2 );
	float b = lua_tonumber( s, 3 );
	
	if( lua_gettop( s ) > 3 )
	{
		float a = lua_tonumber( s, 4 );
		Draw::Color4f( r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f );
	} 
	
	return 0;
	
}

int LUA_DrawSetColor( lua_State * s )
{
	
	float r = lua_tonumber( s, 1 );
	float g = lua_tonumber( s, 2 );
	float b = lua_tonumber( s, 3 );
	
	if( lua_gettop( s ) > 3 )
	{
		float a = lua_tonumber( s, 4 );
		Draw::Color4f( r, g, b, a );
	} 
	
	return 0;
	
}

int LUA_DrawText( lua_State * s )
{
	
	std::string font = ( char * )lua_tostring( s, 1 );
	std::string text = ( char * )lua_tostring( s, 2 );
	int x = lua_tonumber( s, 3 );
	int y = lua_tonumber( s, 4 );
	
	CFontMaterial * fontmat = GetFont( font );
	
	fontmat->Draw( text, x, y );
	
	return 0;
	
}

int LUA_bindtexture( lua_State * s ) 
{
	

	std::string file = ( char * )lua_tostring( s, 1 );
	
	CMaterial * mat = NULL;
	
	try
	{
		
		mat = m_MappedTextures.at( file );
		
	} catch( std::exception & err )
	{
	
		mat = g_pGameInterface->Graphics()->Find( file );
		
		if( !mat )
			return 0;
		else
		{
			
			m_MappedTextures[file] = mat;
			
		}
		
	}
	
	mat->BindFrame( 0 );
	
	return 0;
	
}

int LUA_DrawTexture( lua_State * s )
{
	
	std::string file = "";
	
	if( lua_isnil( s, 1 ) == 0 )
		file = ( char * )lua_tostring( s, 1 );
	
	int x = lua_tonumber( s, 2 );
	int y = lua_tonumber( s, 3 );
	int w = lua_tonumber( s, 4 );
	int h = lua_tonumber( s, 5 );
	
	CMaterial * mat = NULL;
	
	if( file != "" )
	{
	
		try
		{
			
			mat = m_MappedTextures.at( file );
			
		} catch( std::exception & err )
		{
			
			mat = g_pGameInterface->Graphics()->Find( file );
			
			if( !mat )
				return 0;
			else
			{
				
				m_MappedTextures[file] = mat;
				
			}
			
		}
		
		mat->BindFrame( 0 );
	
	}
	
	Draw::TexturedQuad( x, y, w, h );
	
	return 0;
	
}